#include "stdafx.h"
#include "imscwubi.h"

std::map<std::wstring, int> m_mValues;
std::map<std::wstring, std::wstring> m_mLine;

boolean Imscwubi::LoadFromText(const char * FileName)
{
	m_ifh = NULL;
	Clear();
	m_ifh = new ImscwubiFileHead;
	m_hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)0);
	HANDLE  hMapping = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	unsigned char *line = (unsigned char*)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
	CloseHandle(hMapping);
	CloseHandle(m_hFile);

	boolean bIsUnicode = false;
	boolean bIsUTF8 = false;

	bIsUnicode = (line[0] == 255 && line[1] == 254);
	bIsUTF8 = (line[0] == 239 && line[1] == 187 && line[2] == 191);
	std::wstring wstr;
	if (bIsUnicode)
	{
		wstr = (const wchar_t *)((char *)line + 2);
	}
	else  if (bIsUTF8)
	{
		wstr = PublicFunction::UTF8ToWString((char *)line + 3);
	}
	else
		wstr = PublicFunction::MBytesToWString((char *)line);
	int sPos = 0;
	int ePos = wstr.find(L"\n", 0);
	
	std::map<std::wstring, int>::iterator it;
	std::wstring wsubstr;
	std::wstring szCode;
	std::wstring szValue;
	std::map<std::wstring, std::wstring>::iterator item;
	while (ePos != std::wstring::npos)
	{
		if (sPos != ePos)
		{
			wsubstr = wstr.substr(sPos, ePos - sPos - 1);
			it = m_mValues.find(wsubstr);
			if (it == m_mValues.end())
			{
				m_mValues.insert(std::make_pair(wsubstr, 1));
				int ipos = wsubstr.find(L" ");
				if (ipos > 0)
				{
					szCode = wsubstr.substr(0, ipos);
					if (!PublicFunction::ValidateCode(szCode))
					{
						Clear();
						return false;
					}
					szValue = PublicFunction::replace_all_distinct(wsubstr.substr(ipos + 1, wstr.length() - ipos), L" ", L",");
					item = m_mLine.find(szCode);
					if (item == m_mLine.end())
					{
						m_mLine.insert(std::make_pair(szCode, szValue));
					}
					else
					{
						std::wstring str = item->second + L"," + szValue;
						item->second = str;
					}
				}
			}
		}
		sPos = ePos + 1;
		ePos = wstr.find(L"\n", sPos);
	}

	return true;
}

void Imscwubi::SaveToFile(const char * FileName)
{
	if (m_mLine.size() == 0)
		return;
	char ch = '`';
	m_hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if ((DWORD)m_hFile == INVALID_FILE_SIZE || (DWORD)m_hFile == INVALID_SET_FILE_POINTER || (DWORD)m_hFile == INVALID_FILE_ATTRIBUTES)
	{
		return;
	}
	unsigned char szHead[168] = { 0 };
	WriteData(szHead, 168);//

	int sPos = 0;
	int ePos =0;
	long iCount = 0;
	std::wstring wsubstr;
	std::wstring szCode;
	std::wstring szValue;
	std::map<std::wstring, std::wstring>::iterator item;
	for (item = m_mLine.begin(); item != m_mLine.end(); ++item)
	{
		int len = 0;
		int index = 0;
		szCode = item->first;
		sPos = 0;
		std::wstring sztmp = item->second + L",";
		ePos = sztmp.find(L",");
		if ((int)ch < (int)szCode[0])
		{
			++ch;
			m_ifh->charlen[(int)ch - 97] = iCount;
		}
		if (ePos > 0)
		{
			while (ePos != std::wstring::npos)
			{
				if (sPos != ePos)
				{
					szValue = sztmp.substr(sPos, ePos - sPos);
					if (szValue.size() > 0)
					{
						index++;
						len = Pair(szCode, szValue, index);
						iCount += len;
					}
				}
				sPos = ePos + 1;
				ePos = sztmp.find(L",", sPos);
			}
		}

	}
	if ((int)ch < 122)
	{
		++ch;
		m_ifh->charlen[(int)ch - 97] = iCount;
	}
	PublicFunction::Int32ToByte(168 + iCount, m_ifh->dword3);
	SetFilePointer(m_hFile, 0, 0, FILE_BEGIN);
	WriteData((unsigned char *)m_ifh->FileFlag, 8);
	WriteData((unsigned char *)m_ifh->word1, 2);
	WriteData((unsigned char *)m_ifh->word2, 2);
	WriteData((unsigned char *)m_ifh->dword1, 4);
	WriteData((unsigned char *)m_ifh->dword2, 4);
	WriteData((unsigned char *)m_ifh->dword3, 4);
	WriteData((unsigned char *)m_ifh->dword4, 4);
	WriteData((unsigned char *)m_ifh->empty, 36);
	for (int i = 0; i < 26; i++)
	{
		unsigned char utmp[4] = { 0 };
		PublicFunction::Int32ToByte(m_ifh->charlen[i], utmp);
		WriteData(utmp, 4);
	}

	CloseHandle(m_hFile);
}

int Imscwubi::Pair(std::wstring szCode, std::wstring szValue, int index)
{
	int len = 0;
	len = 14 + szValue.length() * 2 + 2;
	unsigned char * arrayData = new unsigned char[len];
	memset(arrayData, 0, len);
	PublicFunction::EncodePair(szCode, szValue, index, len, arrayData);
	WriteData(arrayData, len);
	delete[] arrayData;
	arrayData = NULL;
	return len;
}

void Imscwubi::Clear()
{
	m_mLine.clear();
	std::map<std::wstring, std::wstring>().swap(m_mLine);
	m_mValues.clear();
	std::map<std::wstring, int>().swap(m_mValues);
	if (m_ifh)
		delete m_ifh;
}

void Imscwubi::WriteData(unsigned char *buffer, DWORD len)
{
	unsigned char *tmpBuf;
	DWORD dwBytesWrite, dwBytesToWrite;
	dwBytesToWrite = len;
	dwBytesWrite = 0;
	tmpBuf = buffer;
	do{
		WriteFile(m_hFile, tmpBuf, dwBytesToWrite, &dwBytesWrite, NULL);
		dwBytesToWrite -= dwBytesWrite;
		tmpBuf += dwBytesWrite;

	} while (dwBytesToWrite > 0);
}

Imscwubi::~Imscwubi()
{
	Clear();
}